const { random } = Math

const randomColor = [
  ['#95e1d3', '#eaffd0', '#fce38a', '#f38181'],
  ['#6a2c70', '#b83b5e', '#f08a5d', '#f9ed69'],
  ['#edb1f1', '#d59bf6', '#9896f1', '#8ef6e4'],
  ['#ff9de2', '#8c82fc', '#b693fe', '#7effdb'],
  ['#fff5a5', '#ffaa64', '#ff8264', '#ff6464']
]

export interface IRibbonOptions {
  zIndex: number;
  alpha: number;
  size: number;
}

interface IRibbonPoint {
  x: number;
  y: number;
}

const getRandomInt = (value: number) => {
  return Math.floor(Math.random() * value)
}

export class Ribbon {
  /**
   * 画布元素
   */
  canvas: HTMLCanvasElement;
  /**
   * Canvas中的Context
   */
  ctx: CanvasRenderingContext2D;
  /**
   * 轨迹路径
   */
  path: IRibbonPoint[];
  /**
   * 区域宽度
   */
  width: number;
  /**
   * 区域高度
   */
  height: number;
  /**
   * 颜色色系
   */
  colorIndex: number;
  /**
   * 配置项
   */
  options: IRibbonOptions

  constructor(options: IRibbonOptions = {
    alpha: 0.6,
    size: 300,
    zIndex: 0
  }) {
    this.options = options
    // 生成Canvas元素 并添加到Body中
    this.canvas = document.createElement('canvas')
    this.canvas.classList.add('ribbon-canvas')
    this.canvas.style.cssText = `position:fixed;top:0;left:0;z-index:${this.options.zIndex}`
    document.getElementsByTagName('body')[0].appendChild(this.canvas)

    this.ctx = this.canvas.getContext('2d') as CanvasRenderingContext2D
    this.width = window.innerWidth
    this.height = window.innerHeight

    // 返回实际宽高
    const dpr = window.devicePixelRatio || 1
    this.canvas.width = this.width * dpr
    this.canvas.height = this.height * dpr
    // 水平、竖直方向缩放
    this.ctx.scale(dpr, dpr)
    // 图形透明度
    this.ctx.globalAlpha = this.options.alpha
    this.path = []
    this.colorIndex = 0

    this.reDraw()
  }

  /**
   * 重新绘制
   */
  reDraw() {
    // 清除之前绘制的图形
    this.ctx.clearRect(0, 0, this.width, this.height)
    // 生成新的点和路径
    const point1: IRibbonPoint = {
      x: 0,
      y: this.height * 0.7 + this.options.size
    }
    const point2: IRibbonPoint = {
      x: 0,
      y: this.height * 0.7 - this.options.size
    }
    this.path = [point1, point2]
    // 随机选择色系
    this.colorIndex = getRandomInt(randomColor.length)
    // 路径没有填满屏幕宽度时，绘制路径
    while (this.path[1].x < this.width + this.options.size) {
      this.draw(this.path[0], this.path[1])
    }
  }

  /**
   * 绘制线
   * @param start 起点
   * @param end 终点
   */
  draw(start: IRibbonPoint, end: IRibbonPoint) {
    // 绘制当前点
    this.ctx.beginPath()
    this.ctx.moveTo(start.x, start.y)
    this.ctx.lineTo(end.x, end.y)
    const nextX = this.geneX(end.x)
    const nextY = this.geneY(end.y)
    this.ctx.lineTo(nextX, nextY)
    this.ctx.closePath()

    // 随机生成颜色
    const color = randomColor[this.colorIndex]
    this.ctx.fillStyle = `${color[getRandomInt(color.length)]}`
    // 根据当前样式填充路径
    this.ctx.fill()

    // 继续绘制下一个点
    // 起点更新为当前终点
    this.path[0] = this.path[1]
    // 更新终点
    this.path[1] = { x: nextX, y: nextY }
  }

  /**
   * 生成下一个x坐标
   * @param x 当前x坐标
   */
  geneX(x: number) {
    // 当前坐标向上平移
    return x + this.options.size
  }

  /**
   * 生成下一个y坐标
   * @param y 当前y坐标
   */
  geneY(y: number) {
    // 当前坐标向右平移
    const temp = y + (random() * 2 - 1.1) * this.options.size
    return (temp > this.height || temp < 0) ? this.height : temp
  }

  /**
   * 清除画布
   */
  clear() {
    this.canvas.remove()
  }
}

